package entityUpdater

import (
	"gitee.com/fierce_wolf/go-fox-edge-common/commRedisService"
	"gitee.com/fierce_wolf/go-fox-edge-common/commSql"
	"gitee.com/fierce_wolf/go-fox-edge-common/edgeEntity"
	"time"
)

type DeviceStatusValueUpdater struct {
}

func (e *DeviceStatusValueUpdater) updateDeviceStatusValue(deviceEntity *edgeEntity.DeviceEntity, values interface{}) {
	if values == nil {
		return
	}

	statusValues := values.(map[string]interface{})
	if len(statusValues) == 0 {
		return
	}

	// 预处理：对数值进行映射的处理
	e.mappingStatusValues(deviceEntity, statusValues)
	// 预处理：对预处理的结果，再进行一次预处理，达到二次映射的效果。
	e.mappingStatusValues(deviceEntity, statusValues)

	// 保存设备类型的结构化息
	e.saveObjInfEntity(deviceEntity, statusValues)

	// 构建数值实体
	valueEntity := e.buildValueEntity(deviceEntity, statusValues)

	// 从redis读取原有的数值实体
	existEntity, err := commRedisService.GetEntityByServiceKey(valueEntity.Type(), valueEntity.MakeServiceKey())
	if err != nil {
		return
	}

	// 步骤1：将数据保存到redis，同时也生成设备对象，保存到mysql数据库中
	e.saveValueEntity(existEntity, valueEntity)

	// 步骤2：将数值保存到历史记录
	DeviceHistoryAdapter.SaveHistoryEntity(existEntity, statusValues)

}

func (e *DeviceStatusValueUpdater) mappingStatusValues(deviceEntity *edgeEntity.DeviceEntity, statusValues map[string]interface{}) (map[string]interface{}, error) {
	deviceMapper, err := deviceObjectMapper.getDeviceValue(deviceEntity.Manufacturer, deviceEntity.DeviceType)
	if err != nil || deviceMapper == nil {
		return statusValues, nil
	}

	result := make(map[string]interface{})
	for key, val := range statusValues {
		// 如果没有该配置，那么沿用原来的数值
		mapper, err := deviceObjectMapper.getObjectValue(deviceEntity.Manufacturer, deviceEntity.DeviceType, key)
		if err != nil || mapper == nil {
			result[key] = val
			continue
		}

		// 场景1：保留原始值
		if mapper.Value == mapperModeOriginal {
			result[key] = val
			continue
		}

		// 场景2：采用一个新值
		if mapper.Value == mapperModeReplace {
			result[mapper.Key.(string)] = val
			continue
		}

		// 场景3：保留原始值，并复制一个新值
		if mapper.Value == mapperModeDuplicate {
			result[key] = val
			result[mapper.Key.(string)] = val
			continue
		}

		// 场景4：剔除该值
		if mapper.Value == mapperModeFilter {
			continue
		}

		// 场景5：展开
		if mapper.Value == mapperModeExpend {
			value := val
			switch value.(type) {
			case map[string]interface{}:
				e.expendMapper(val.(map[string]interface{}), key, result)
				break
			default:
				result[key] = val
				break
			}
			continue
		}
	}

	return result, nil

}

func (e *DeviceStatusValueUpdater) expendMapper(data map[string]interface{}, path string, expendMap map[string]interface{}) {
	for key, value := range data {
		subKey := path + "_" + key

		switch value.(type) {
		case map[string]interface{}:
			e.expendMapper(value.(map[string]interface{}), subKey, expendMap)
			break
		default:
			expendMap[subKey] = value
			break
		}
	}
}

func (e *DeviceStatusValueUpdater) buildValueEntity(deviceEntity *edgeEntity.DeviceEntity, statusValues map[string]interface{}) *edgeEntity.DeviceValueEntity {
	updateTime := time.Now().UnixMilli()

	// 构造更新数值
	valueEntity := edgeEntity.Type.DeviceValueEntity.Instance()
	valueEntity.BaseEntity.Id = deviceEntity.BaseEntity.Id
	valueEntity.DeviceType = deviceEntity.DeviceType
	valueEntity.Manufacturer = deviceEntity.Manufacturer
	valueEntity.DeviceName = deviceEntity.DeviceName
	for key, value := range statusValues {
		deviceObjectValue := &edgeEntity.DeviceObjectValue{}
		deviceObjectValue.Value = value
		deviceObjectValue.Time = updateTime
		valueEntity.Params[key] = deviceObjectValue

	}

	return valueEntity
}

func (e *DeviceStatusValueUpdater) saveObjInfEntity(deviceEntity *edgeEntity.DeviceEntity, statusValues map[string]interface{}) {
	if deviceEntity == nil {
		return
	}

	// 将新增的数据，作为对象保存到数据库
	for key, value := range statusValues {
		entity := edgeEntity.Type.DeviceObjInfEntity.Instance()
		entity.Manufacturer = deviceEntity.Manufacturer
		entity.DeviceType = deviceEntity.DeviceType
		entity.ObjectName = key

		if value == nil {
			continue
		}

		// 转换类型标识
		switch value.(type) {
		case string:
			entity.ValueType = "String"
			break
		case float64:
			entity.ValueType = "Double"
			break
		case float32:
			entity.ValueType = "Float"
			break
		case int64:
			entity.ValueType = "Long"
			break
		case int32:
			entity.ValueType = "Int"
			break
		case bool:
			entity.ValueType = "Boolean"
			break
		default:
			entity.ValueType = "Object"
			continue
		}

		// 检查：是否已经存在
		has, err := commRedisService.HasEntityByServiceKey(entity.Type(), entity.MakeServiceKey())
		if err != nil || has {
			continue
		}

		// 保存数据
		commRedisService.InsertEntity(entity)
	}
}

func (e *DeviceStatusValueUpdater) saveValueEntity(existEntity interface{}, valueEntity *edgeEntity.DeviceValueEntity) {
	// 步骤2：将数据保存到redis，同时也生成设备对象，保存到mysql数据库中
	if existEntity == nil {
		// 将新增的数据，作为对象保存到数据库
		e.saveObjectEntities(valueEntity)

		// 保存数据到redis
		updateTime := time.Now().UnixMilli()
		valueEntity.BaseEntity.CreateTime = updateTime
		valueEntity.BaseEntity.UpdateTime = updateTime
		commRedisService.InsertEntity(valueEntity)
	} else {
		exist := existEntity.(*edgeEntity.DeviceValueEntity)

		// 将新增的数据，作为对象保存到数据库
		for key := range valueEntity.Params {
			_, ok := exist.Params[key]
			if !ok {
				e.saveObjectEntity(valueEntity.DeviceName, valueEntity.Manufacturer, valueEntity.DeviceType, key)
			}
		}

		// 合并数据
		for key := range exist.Params {
			_, ok := valueEntity.Params[key]
			if !ok {
				valueEntity.Params[key] = exist.Params[key]
			}
		}

		// 更新
		updateTime := time.Now().UnixMilli()
		valueEntity.BaseEntity.UpdateTime = updateTime
		commRedisService.UpdateEntity(valueEntity)
	}
}

func (e *DeviceStatusValueUpdater) saveObjectEntities(valueEntity *edgeEntity.DeviceValueEntity) {
	deviceObjectEntity := edgeEntity.Type.DeviceObjectEntity.Instance()
	deviceObjectEntity.DeviceName = valueEntity.DeviceName

	// 数据库侧的Keys:通过查询设备级别的数据
	sql, err := commSql.SQL.SelectWhere(deviceObjectEntity.Type(), "device_name='"+deviceObjectEntity.DeviceName+"'")
	if err != nil {
		return
	}
	entityList, err := commSql.Query(deviceObjectEntity.Type(), sql)
	if err != nil {
		return
	}

	// 构造一个整个设备的对象列表
	dbServiceKeys := make(map[string]interface{})
	for _, entity := range entityList {
		dbServiceKeys[entity.MakeServiceKey()] = entity
	}

	// 将新增的数据，作为对象保存到数据库
	for key := range valueEntity.Params {
		deviceObjectEntity = edgeEntity.Type.DeviceObjectEntity.NewEntity().(*edgeEntity.DeviceObjectEntity)
		deviceObjectEntity.DeviceName = valueEntity.DeviceName
		deviceObjectEntity.Manufacturer = valueEntity.Manufacturer
		deviceObjectEntity.DeviceType = valueEntity.DeviceType
		deviceObjectEntity.ObjectName = key

		serviceKey := deviceObjectEntity.MakeServiceKey()
		_, ok := dbServiceKeys[serviceKey]
		if ok {
			continue
		}

		// 写入数据库
		commSql.InsertEntity(deviceObjectEntity)

		// 更新数据库变更的时间
		//		this.entityPublishManager.setPublishEntityUpdateTime(DeviceObjectEntity.class.getSimpleName(), System.currentTimeMillis());

	}
}

func (e *DeviceStatusValueUpdater) saveObjectEntity(deviceName string, manufacturer string, deviceType string, objectName string) {
	deviceObjectEntity := edgeEntity.Type.DeviceObjectEntity.NewEntity().(*edgeEntity.DeviceObjectEntity)
	deviceObjectEntity.DeviceName = deviceName
	deviceObjectEntity.Manufacturer = manufacturer
	deviceObjectEntity.DeviceType = deviceType
	deviceObjectEntity.ObjectName = objectName

	// 生成SQL语句
	sql, err := commSql.SQL.SelectWhere(deviceObjectEntity.Type(), "device_name = '"+deviceName+"' AND object_name = '"+objectName+"'")
	if err != nil {
		return
	}

	// 查询数据是否在数据库中存在
	exists, err := commSql.Query(deviceObjectEntity.Type(), sql)
	if err != nil {
		return
	}
	if len(exists) > 0 {
		return
	}

	// 写入数据库
	commSql.InsertEntity(deviceObjectEntity)
}

func (e *DeviceStatusValueUpdater) deleteValueEntity(deviceName string, objectNameList []string) {
	// 从redis中读取deviceValue数据
	find := edgeEntity.Type.DeviceValueEntity.Instance()
	find.DeviceName = deviceName
	existEntity, err := commRedisService.GetEntityByServiceKey(find.Type(), find.MakeServiceKey())
	if err != nil {
		return
	}

	// 步骤1：删除redis的deviceValue.param数据
	if existEntity != nil {
		valueEntity := existEntity.(*edgeEntity.DeviceValueEntity)

		// 删除副本中的对象
		for _, objectName := range objectNameList {
			delete(valueEntity.Params, objectName)
		}

		// 把副本更新到redis中
		valueEntity.BaseEntity.UpdateTime = time.Now().UnixMilli()
		commRedisService.UpdateEntity(existEntity)
	}

	// 步骤2：删除mysql中的deviceObject数据
	for _, objectName := range objectNameList {
		// 删除对象
		deviceObjectEntity := edgeEntity.Type.DeviceObjectEntity.Instance()
		deviceObjectEntity.DeviceName = deviceName
		deviceObjectEntity.ObjectName = objectName

		// 构造删除数据库语句
		sql, err := commSql.SQL.DeleteWhere(deviceObjectEntity.Type(), "device_name = '"+deviceName+"' AND object_name = '"+objectName+"'")
		if err != nil {
			return
		}

		// 在数据库中执行SQL
		commSql.Client.Exec(sql, nil)
	}
}
